/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "hks_access_control_test_common.h"

static struct HksParam AuthToken_Import_Params[] = {
    { 
        .tag = HKS_TAG_ALGORITHM, 
        .uint32Param = HKS_ALG_HMAC 
    },{ 
        .tag = HKS_TAG_PURPOSE, 
        .uint32Param = HKS_KEY_PURPOSE_MAC 
    },{ 
        .tag = HKS_TAG_KEY_SIZE, 
        .uint32Param = HKS_AES_KEY_SIZE_256 
    },{ 
        .tag = HKS_TAG_DIGEST, 
        .uint32Param = HKS_DIGEST_SHA256 
    }
};

static struct HksParam AuthToken_HMAC_Params[] = {
    {
        .tag = HKS_TAG_ALGORITHM,
        .uint32Param = HKS_ALG_HMAC
    }, {
        .tag = HKS_TAG_PURPOSE,
        .uint32Param = HKS_KEY_PURPOSE_MAC
    }, {
        .tag = HKS_TAG_DIGEST,
        .uint32Param = HKS_DIGEST_SHA256
    }
};

int32_t AuthTokenImportKey()
{
    struct HksParamSet *importParamSet = nullptr;
    int32_t ret = InitParamSet(&importParamSet, AuthToken_Import_Params, sizeof(AuthToken_Import_Params) / sizeof(HksParam));
    if (ret != HKS_SUCCESS) {
        return ret;
    }
    struct HksBlob key = { SHA256_KEY_LEN, (uint8_t*)HKS_DEFAULT_USER_AT_KEY };

    uint8_t alias[] = "AuthToken_Sign_Verify_KeyAlias";
    struct HksBlob keyAlias = { sizeof(alias), alias };
    ret = HksImportKey(&keyAlias, importParamSet, &key);
    HksFreeParamSet(&importParamSet);
    HksFree(key.data);
    return ret;
}

int32_t AuthTokenSign(struct HksBlob *challenge, uint64_t secureUid, uint64_t enrolledId, uint64_t time, std::vector<uint8_t>& token)
{
    int32_t ret = HKS_FAILURE;
    const char *keyAliasString = "AuthToken_Sign_Verify_KeyAlias";
    const struct HksBlob keyAlias = { strlen(keyAliasString), (uint8_t *)keyAliasString };
    UserAuthTokenHal *authTokenHal = (struct UserAuthTokenHal *)HksMalloc(AUTH_TOKEN_LEN);
    if (authTokenHal == NULL) {
        HKS_LOG_E("could not alloc memory");
        return HKS_FAILURE;
    }
    if(time == 0) {
        authTokenHal->time = OHOS::MiscServices::TimeServiceClient::GetInstance()->GetBootTimeMs();
    }
    else {
        authTokenHal->time = time;
    }
    authTokenHal->secureUid = secureUid;
    authTokenHal->enrolledId = enrolledId;
    if (memcpy_s(authTokenHal->challenge, TOKEN_CHALLENGE_LEN, challenge->data, challenge->size) != EOK) {
        return HKS_FAILURE;
    }
    uint8_t authTokenData[AUTH_TOKEN_DATA_LEN] = {0};
    if (memcpy_s(authTokenData, AUTH_TOKEN_DATA_LEN, authTokenHal, AUTH_TOKEN_DATA_LEN) != EOK) {
        return HKS_FAILURE;
    }
    struct HksBlob inData = { AUTH_TOKEN_DATA_LEN, authTokenData };

    struct HksParamSet *hmacParamSet = nullptr;
    ret = InitParamSet(&hmacParamSet, AuthToken_HMAC_Params, sizeof(AuthToken_HMAC_Params) / sizeof(HksParam));
    if (ret != HKS_SUCCESS) {
        HKS_LOG_E("InitsignParamSet failed");
        return ret;
    }
    /// Init
    uint8_t handle[sizeof(uint64_t)] = {0};
    struct HksBlob handleHMAC = { sizeof(uint64_t), handle };
    ret = HksInit(&keyAlias, hmacParamSet, &handleHMAC);
    if (ret != HKS_SUCCESS) {
        HKS_LOG_E("Init failed");
        HksFreeParamSet(&hmacParamSet);
        return ret;
    }
    // Update & Finish
    struct HksBlob outData = { SHA256_SIGN_LEN, authTokenHal->sign };
    ret = TestUpdateFinish(&handleHMAC, hmacParamSet, HKS_KEY_PURPOSE_MAC, &inData, &outData);
    if (ret != HKS_SUCCESS) {
        HKS_LOG_E("Update&Finish failed");
        HksFreeParamSet(&hmacParamSet);
        return ret;
    }

    for (uint32_t i = 0; i < AUTH_TOKEN_DATA_LEN; i++){
        token.push_back(authTokenData[i]);
    }
    for (uint32_t i = 0; i < SHA256_SIGN_LEN; i++){
        token.push_back(authTokenHal->sign[i]);
    }
    HksFreeParamSet(&hmacParamSet);
    return  HKS_SUCCESS;
}